﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
using System.Windows.Shapes;

namespace GenUI.WPF.GenControls
{
    public class GenChart : Control
    {
        Canvas PART_canvas;
        UniformGrid PART_ug;
        public double MaxX { get; set; } = 100;
        public double MinX { get; set; } = 0;
        public double MaxY { get; set; } = 100;
        public double MinY { get; set; } = 0;
        public int StepX { get; set; } = 10;
        public int StepY { get; set; } = 10;
        public double IdealValue { get; set; } = 80;
        public double MaxValue { get; set; } = 90;
        public double MinValue { get; set; } = 70;
        public Dictionary<string, Polyline> LinesDic { get; private set; } = new Dictionary<string, Polyline>();
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            this.SizeChanged += (_, e) => Refresh();
            PART_canvas = GetTemplateChild("PART_canvas") as Canvas;
            PART_ug = GetTemplateChild("PART_ug") as UniformGrid;
        }
        public void AddLine(string lineName, Brush brush)
        {
            if (!LinesDic.ContainsKey(lineName))
            {
                Polyline line = new Polyline
                {
                    Stroke = brush
                };
                LinesDic.Add(lineName, line);
                if (PART_ug != null)
                {
                    PART_ug.Children.Clear();
                    foreach (var item in LinesDic)
                    {
                        PART_ug.Children.Add(new Label() { Background = item.Value.Stroke, Margin = new Thickness(3, 20, 1, 0) });
                        PART_ug.Children.Add(new TextBlock() { Text = item.Key, Margin = new Thickness(1, 20, 3, 0), VerticalAlignment = VerticalAlignment.Center, HorizontalAlignment = HorizontalAlignment.Left });
                    }
                }
            }
            else
            {
                throw new Exception($"key:{lineName}已存在");
            }
        }
        public void Add(string lineName, double y)
        {
            if (!LinesDic.ContainsKey(lineName)) return;
            this.Dispatcher.BeginInvoke(new Action(() =>
            {
                double xx = (LinesDic[lineName].Points.Count) * ((StepX * (ActualWidth - 50)) / (MaxX - MinX));
                double yy = ((MaxY - y + MinY) * (ActualHeight - 50)) / (MaxY - MinY);
                LinesDic[lineName].Points.Add(new Point(xx, yy));
                Refresh();
            }));
        }
        private void Refresh()
        {
            if (PART_canvas == null) return;
            PART_canvas.Children.Clear();
            double scx = ((StepX * (ActualWidth - 50)) / (MaxX - MinX));
            int nx = (int)((MaxX - MinX) / StepX);

            double scy = ((StepY * (ActualHeight - 50)) / (MaxY - MinY));
            int ny = (int)((MaxY - MinY) / StepY);

            foreach (var item in LinesDic.Values)
            {
                if (item != null && item.Points.Count > nx)
                {
                    for (int i = 0; i < item.Points.Count; i++)
                    {
                        double x = item.Points[i].X - scx;
                        double y = item.Points[i].Y;
                        item.Points[i] = new Point(x, y);
                    }
                    item.Points.RemoveAt(0);
                }
                if (item != null)
                    PART_canvas.Children.Add(item);
            }

            Line lineX = new Line
            {
                X1 = 0,
                Y1 = ActualHeight - 50,
                X2 = ActualWidth - 50,
                Y2 = ActualHeight - 50,
                Stroke = Brushes.Red,
                StrokeThickness = 2,
            };
            Line lineY = new Line
            {
                X1 = 0,
                Y1 = ActualHeight - 50,
                X2 = 0,
                Y2 = -50,
                Stroke = Brushes.Red,
                StrokeThickness = 2
            };
            var convert = TypeDescriptor.GetConverter(typeof(Geometry));
            Path pathX = new Path()
            {
                Fill = Brushes.Red,
                Data = (Geometry)convert.ConvertFrom($"M{ActualWidth - 60},{ActualHeight - 55} L{(ActualWidth - 50)},{(ActualHeight - 50)} L{ActualWidth - 60},{ActualHeight - 45} L{ActualWidth - 54},{(ActualHeight - 50)} Z"),
                Stroke = Brushes.Red,
            };
            Path pathY = new Path()
            {
                Fill = Brushes.Red,
                Data = (Geometry)convert.ConvertFrom($"M-5,4 L0,-6 L5,4 L0,0 Z"),
                Stroke = Brushes.Red,
            };
            PART_canvas.Children.Add(lineX);
            PART_canvas.Children.Add((lineY));
            PART_canvas.Children.Add(pathX);
            PART_canvas.Children.Add(pathY);

            Line IdealValueline = new Line()
            {
                X1 = 0,
                Y1 = (MaxY - IdealValue + MinY) * (ActualHeight - 50) / (MaxY - MinY),
                X2 = (ActualWidth - 50),
                Y2 = (MaxY - IdealValue + MinY) * (ActualHeight - 50) / (MaxY - MinY),
                Stroke = Brushes.Green,
                StrokeThickness = 1.5,
            };
            Line MaxValueline = new Line()
            {
                X1 = 0,
                Y1 = (MaxY - MaxValue + MinY) * (ActualHeight - 50) / (MaxY - MinY),
                X2 = (ActualWidth - 50),
                Y2 = (MaxY - MaxValue + MinY) * (ActualHeight - 50) / (MaxY - MinY),
                Stroke = Brushes.Green,
                StrokeThickness = 1,
            };
            Line MinValueline = new Line()
            {
                X1 = 0,
                Y1 = (MaxY - MinValue + MinY) * (ActualHeight - 50) / (MaxY - MinY),
                X2 = (ActualWidth - 50),
                Y2 = (MaxY - MinValue + MinY) * (ActualHeight - 50) / (MaxY - MinY),
                Stroke = Brushes.Green,
                StrokeThickness = 1,
            };
            PART_canvas.Children.Add(IdealValueline);
            PART_canvas.Children.Add(MaxValueline);
            PART_canvas.Children.Add(MinValueline);
            for (int x = 0; x < nx; x++)
            {
                Line line = new Line
                {
                    X1 = x * scx,
                    Y1 = this.ActualHeight - 50,
                    X2 = x * scx,
                    Y2 = this.ActualHeight - 60,
                    Stroke = Brushes.Red,
                    StrokeThickness = 2
                };
                TextBlock textBlock = new TextBlock()
                {
                    Text = (StepX * x).ToString(),
                    FontSize = 13,
                    Height = 15,
                    Width = (ActualWidth - 50) / nx,
                    VerticalAlignment = VerticalAlignment.Center,
                    HorizontalAlignment = HorizontalAlignment.Center,
                };
                PART_canvas.Children.Add(line);
                PART_canvas.Children.Add(textBlock);
                Canvas.SetBottom(textBlock, -20);
                Canvas.SetLeft(textBlock, (x * scx) - 6);
            }
            for (int y = 0; y < ny; y++)
            {
                Line line = new Line
                {
                    Y1 = -y * scy + ActualHeight - 50,
                    X1 = 0,
                    Y2 = -y * scy + ActualHeight - 50,
                    X2 = 10,
                    Stroke = Brushes.Red,
                    StrokeThickness = 2
                };
                TextBlock textBlock = new TextBlock()
                {
                    Text = (StepY * y).ToString(),
                    FontSize = 13,
                    Height = (ActualHeight - 50) / ny,
                    Width = 30,
                    VerticalAlignment = VerticalAlignment.Center,
                    HorizontalAlignment = HorizontalAlignment.Left,
                };
                PART_canvas.Children.Add(line);
                PART_canvas.Children.Add(textBlock);
                Canvas.SetLeft(textBlock, -30);
                Canvas.SetBottom(textBlock, (y * scy) - textBlock.Height / 1.3);
            }
        }
    }
}
